package com.dzjcloud.dzj.upms.biz.service.impl;

import cn.dev33.satoken.stp.StpUtil;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.lang.Validator;
import cn.hutool.core.map.MapUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.crypto.SecureUtil;

import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.dzjcloud.dzj.common.core.enums.ResultEnum;
import com.dzjcloud.dzj.common.minio.utils.Base64Utils;
import com.dzjcloud.dzj.common.core.exception.HandleException;
import com.dzjcloud.dzj.common.core.utils.GetTime;
import com.dzjcloud.dzj.common.core.utils.RequestIpUtils;
import com.dzjcloud.dzj.common.redis.utils.RedisUtil;
import com.dzjcloud.dzj.upms.api.dto.VerificationCheckDto;
import com.dzjcloud.dzj.upms.api.entity.User;
import com.dzjcloud.dzj.upms.api.feign.FaceFeginService;
import com.dzjcloud.dzj.upms.api.form.UpdateUserPasswrodForm;
import com.dzjcloud.dzj.upms.api.form.UserRegisteredForm;
import com.dzjcloud.dzj.upms.biz.mapper.UserMapper;
import com.dzjcloud.dzj.upms.biz.service.FileService;
import com.dzjcloud.dzj.upms.biz.service.UserService;
import lombok.Getter;
import lombok.Setter;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import java.io.File;
import java.time.LocalDate;
import java.util.*;

/**
 * <h3>springbootdemo</h3>
 * <p>用户服务实现类</p>
 *
 * @author : DongZeJian
 * @date : 2020-04-28 10:43
 **/
@Service
@Slf4j
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements UserService {

    @Autowired
    private RedisUtil redisUtil;

    @Autowired
    private FileService fileService;

    private FaceFeginService faceFeginService;

   // @Value("${Face.api_key}")
    @Getter
    @Setter
    private String api_key;

    //@Value("${Face.api_secret}")
    @Getter
    @Setter
    private String api_secret;

    /**
     *  用户注册
     *
     * @param userRegisteredForm 用户注册表单
     * @return 注册结果
     */
    @Override
    public Boolean registered(UserRegisteredForm userRegisteredForm) {
        //TODO 1校验
        //获得用户IP
        String ipAddr = RequestIpUtils.getIpAddr();
        //校验验证码
        VerificationCheckDto verificationCheckDto = Validator.validateNotNull(JSON.parseObject((String)redisUtil.get(ipAddr), VerificationCheckDto.class), "先请求验证码");
        Validator.validateEqual(userRegisteredForm.getVerification(),verificationCheckDto.getVerificationCode(),"验证不正确");
        //校验手机号码是否已注册
        Validator.validateTrue(baseMapper.selectCount(Wrappers.<User>lambdaQuery().eq(User::getPhone, userRegisteredForm.getPhone()).or().eq(User::getUserCode,userRegisteredForm.getUserCode()))<1,
                "该号码已注册过或账号已存在！");

        //TODO 2添加
        User user = BeanUtil.copyProperties(userRegisteredForm, User.class);
        user.setId(GetTime.getGuid());
        user.setPasswrod(SecureUtil.md5(user.getPasswrod()));
        //以上验证通过删除验证码
        redisUtil.del(ipAddr);
        return user.insert();
    }

    /**
     *  修改密码
     *
     * @param updateUserPasswrodForm 修改用户密码表单
     * @return 修改结果
     */
    @Override
    public Boolean updateUserPasswrod(UpdateUserPasswrodForm updateUserPasswrodForm) {
        User user = baseMapper.selectById(String.valueOf(StpUtil.getLoginId()));
        //获得用户IP
        String ipAddr = RequestIpUtils.getIpAddr();
        //校验验证码
        VerificationCheckDto verificationCheckDto = Validator.validateNotNull(JSON.parseObject((String)redisUtil.get(ipAddr), VerificationCheckDto.class), "先请求验证码");
        Validator.validateEqual(updateUserPasswrodForm.getVerification(),verificationCheckDto.getVerificationCode(),"验证不正确");
        //校验原密码
        Validator.validateEqual(SecureUtil.md5(updateUserPasswrodForm.getPasswrod()),user.getPasswrod(),"原密码不正确");
        //校验新旧密码相同
        Validator.validateTrue(!StrUtil.equals(updateUserPasswrodForm.getNewPasswrod(),updateUserPasswrodForm.getPasswrod()),"原密码不能和新密码相同");

        user.setPasswrod(SecureUtil.md5(updateUserPasswrodForm.getNewPasswrod()));
        return user.updateById();
    }

    /**
     *  实名认证
     *
     * @param file 文件
     * @param side 身份证的国徽面或人像面(front: 人像面、back: 国徽面)
     * @TODO 上传身份证第三方会失败 待以后修改为 前端单独调用 第三方上传身份证图片识别然后调用更新接口
     * @return
     */
    @SneakyThrows
    @Override
    public Boolean realNameAuth(MultipartFile file,String side) {
        User user = baseMapper.selectById(String.valueOf(StpUtil.getLoginId()));
        //先把图片上传到minio文件服务
        Map<String, String> fileMap= fileService.uploadFileToCenter(file, 1);
        //识别身份证
        File file1 = Base64Utils.MultipartFileToFile(file);
        Map map = faceFeginService.idCardIdentify(api_key,api_secret,file1);
        Validator.validateEmpty(MapUtil.getStr(map,"error_message"),MapUtil.getStr(map,"error_message"));
        //校验是否上传的是身份证
        if (CollUtil.isEmpty(map)||CollUtil.isEmpty(MapUtil.get(map,"cards", List.class))){
            fileService.deletefile(MapUtil.getStr(fileMap, "fileName"), 1);
            throw new HandleException(ResultEnum.UPLOAD_ERROR_CODE.getCode(),"请上传清晰的身份证照片");
        }
        //校验正反面是否上传正确
        List<Map> cards = MapUtil.get(map, "cards", List.class);
        Map cardMap = cards.get(0);
        if (!StrUtil.equals(side,MapUtil.getStr(cardMap,"side"))){
            fileService.deletefile(MapUtil.getStr(fileMap, "fileName"), 1);
            throw new HandleException(ResultEnum.UPLOAD_ERROR_CODE.getCode(),"请在正确的位置上传身份证");
            //正面实名赋值
        }else if(side.equals("front")){
            //校验当前身份证是否已绑定用户超过3个
            String idCard = MapUtil.getStr(cardMap, "id_card_number");

            if (baseMapper.selectCount(Wrappers.<User>lambdaQuery().eq(User::getIdCard,idCard))>=3){
                fileService.deletefile(MapUtil.getStr(fileMap, "fileName"), 1);
                throw new HandleException(ResultEnum.UPLOAD_ERROR_CODE.getCode(),"该身份证已绑定3个用户或以上不能在实名");
            }
            user.setSex(MapUtil.getStr(cardMap, "gender").equals("女")?2:1);
            user.setUserName(MapUtil.getStr(cardMap, "name"));
            user.setIdCard(idCard);
            user.setBirth(LocalDate.parse(MapUtil.getStr(cardMap, "birthday")));

            //反面实名赋值
        }else if(side.equals("back")){
            user.setIdCardIssueAt(MapUtil.getStr(cardMap, "issued_by"));
            String[] validDates = MapUtil.getStr(cardMap, "valid_date").split("-");
            user.setIdCardEffectiveStrat(validDates[0]);
            user.setIdCardEffectiveEnd(validDates[1]);
        }
        //判断是否属于实名完成
        if (StrUtil.isNotBlank(user.getIdCardIssueAt())){
            user.setIsRealName(true);
        }
        return user.updateById();
    }

    /**
     *  更新头像
     *
     * @param file 文件
     * @return
     */
    @Override
    public Boolean updateHead(MultipartFile file) {
        //获取当前登录人信息
        User user = baseMapper.selectById(String.valueOf(StpUtil.getLoginId()));
        //先把图片上传到minio文件服务
        Map<String, String> fileMap= fileService.uploadFileToCenter(file, 1);
        user.setHederUrl(MapUtil.getStr(fileMap, "fileName"));
        return user.updateById();
    }
}
